using System;
using System.Configuration;
using System.Diagnostics;

using System.Net;
using System.IO;
using System.Text;
using System.Threading;
using System.Web;


namespace crossBow1
{
	/// <summary>
	/// Summary description for Class1.
	/// </summary>
	/// 

	


	class Arrow
	{	
		
		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		/// 
		private  static int numhits;
		private  static int waitbetweenhits;
        private static int waittolaunchthreads; 
		private  static int numthreads; 
		private  static int gettimeout; 			
		private  static int posttimeout; 
		private static string getpage;
		private static string postpage;
		private static String nVs;
        private static bool isGet=true;
        private static string[] getPageValues, VALS;
        private static Random rnd;
        public static ManualResetEvent allDone = new ManualResetEvent(false);


		[STAThread]
		static void Main(string[] args)
		{

        waittolaunchthreads
                = Int32.Parse(ConfigurationManager.AppSettings["waittolaunchthreads"]);
		
		waitbetweenhits 
			= Int32.Parse(ConfigurationManager.AppSettings["waitbetweenhits"]);

		numhits
                = Int32.Parse(ConfigurationManager.AppSettings["numpagehits"]);
		
		numthreads =
            Int32.Parse(ConfigurationManager.AppSettings["numthreads"]);
		
		gettimeout
            = Int32.Parse(ConfigurationManager.AppSettings["getwebrequesttimeout"]);
		
		posttimeout
            = Int32.Parse(ConfigurationManager.AppSettings["postwebrequesttimeout"]);

        getPageValues = @ConfigurationManager.AppSettings["getpagevalues"].Split(';');

        getpage = ConfigurationManager.AppSettings["getpageurl"] + @"?"
              
              + @ConfigurationManager.AppSettings["getpagevalues"];

        VALS = getURLVars();

        rnd = new Random();
        

        string runget = ConfigurationManager.AppSettings["runget"];

        if (!runget.Equals("true")) isGet = false;

       postpage
            = @ConfigurationManager.AppSettings["postpage"];

		nVs=nameValuePairs();

            


			log("Crossbow starts...");
			
			log(numthreads + " Threads launching");
			Thread[] t = new Thread[numthreads];

			for ( int i=0; i< numthreads ; i++) 
			{

				t[i] = new Thread(new ThreadStart(quiver));
                t[i].IsBackground = false;
				t[i].Name="T-"+i.ToString();
                log("Launching " + t[i].Name);
				t[i].Start();
                Thread.Sleep(waittolaunchthreads);
			}

            bool oneLeft = true;

            while (oneLeft)
            {
                oneLeft = false;
                for (int i = 0; i < numthreads; i++)
                {

                    if (t[i].IsAlive) oneLeft = true;
                    //t[i].Join();
                    Thread.Sleep(30000);

                }
            }

            allDone.WaitOne();
			log("Main for Crossbow ends...");
			
			return;
		
			
		
		}


		public static void quiver() 
		{
			string tinfo = Thread.CurrentThread.Name + ":";
            int tnum = Int32.Parse(Thread.CurrentThread.Name.Split('-')[1]);

			for(int n = 0; n<numhits; n++)
			{
				Thread.Sleep(waitbetweenhits);

				//log( "Thread Launching " + Thread.CurrentThread.Name );
				if(isGet) 
                  //getPage(getpage+getPageValues[tnum], tinfo+n); 
                    getPage(getpage + VALS[rnd.Next(VALS.Length)], tinfo + n);
                else
				  postPage(postpage, nVs, tinfo+n);
				
			}
		}


		public static String nameValuePairs()
		{
			StringBuilder nvprs = new StringBuilder();
			
			//To be used to scatter values
			//Random r = new Random();

			TextReader tr = null;
			string input = null;
			string[] pair = new string[2];
			
			try 
			{
				tr = new StreamReader("fieldpairs.txt");
				while ((input = tr.ReadLine()) != null)
				{
					pair = input.Split(',');
					nvprs.Append(pair[0].Replace("\"","")).Append("=").Append(pair[1].Replace("\"","")).Append("&"); 
				}
			} 
			catch (Exception e) 
			{
				log(e.ToString());
			}
			finally 
			{
				tr.Close();
				tr=null;
			}
		
			return nvprs.ToString();
		}

        private static void ScanTimeoutCallback(object state, bool timedOut)
        {
            if (timedOut)
            {
                RequestState reqState = (RequestState)state;
                log(reqState._threadInfo + " timed out to " + reqState._url);
                
                if (reqState != null)
                    reqState._request.Abort();

                
            }
        }

        public static void getPage(string url, string tname)
        {

            CookieContainer CC = new CookieContainer();
            System.Net.ServicePointManager.Expect100Continue = false; 
            HttpWebRequest Req = (HttpWebRequest)WebRequest.Create(url);
            Req.Proxy = null;
            Req.UseDefaultCredentials = true;
            
            Req.CookieContainer = CC;
            Req.Timeout = gettimeout;
            Req.Method = "GET";
            Req.KeepAlive = false;
            Req.Pipelined = false;
            Req.AllowWriteStreamBuffering = true;
           
            

            //WebResponse webResponse=null;
            

            String sTxt=string.Empty;

            try
            {

                RequestState state = new RequestState(Req, tname, url);

                IAsyncResult ar = Req.BeginGetResponse(
                    new AsyncCallback(ResponseCallBack), 
                    state);
                //webResponse = Req.GetResponse();

                
                //sTxt = new System.IO.StreamReader(webResponse.GetResponseStream(),
                //    Encoding.Default).ReadToEnd();

                log(tname + " Request Made " + url);

                ThreadPool.RegisterWaitForSingleObject(
                    ar.AsyncWaitHandle,
                    new WaitOrTimerCallback(ScanTimeoutCallback), state, gettimeout, true);

            }
            catch (Exception e)
            {
                log("ERR:" + e.ToString() + ":" + tname + " GET Error for " + url, true);
            }  
			finally 
			{
                //if(webResponse!=null)
                //webResponse.Close();
			}


        }


        private static void ResponseCallBack(IAsyncResult r)
        {

            RequestState state=null;
            WebRequest request=null;
            HttpWebResponse webResponse=null;

            try
            {

                state = (RequestState)r.AsyncState;
                request = (WebRequest)state._request;
                webResponse = (HttpWebResponse)request.EndGetResponse(r);

                string sTxt = new System.IO.StreamReader(webResponse.GetResponseStream(),
                        Encoding.Default).ReadToEnd();

                log(state._threadInfo + " Successful Request Made " + ":" + sTxt.Substring(sTxt.IndexOf("lbl_mname"),50));
                //log(state._threadInfo + " Successful Request Made " + state._url );
            }
            catch (Exception e)
            {
                log("ERR:" + e.ToString() + ":" + state._threadInfo + " GET Error for " + state._url, true);
            }
            finally
            {
                if (webResponse != null)
                    webResponse.Close();
            }
        } 


		public static void getPage2(string url, string tname)
		{
		// Initialize the WebRequest.
		WebRequest req = WebRequest.Create(url);
        
		req.Timeout = gettimeout;
		WebResponse  result=null;

			try
			{
				result = req.GetResponse();
				Stream ReceiveStream = result.GetResponseStream();

				
				
				byte[] read = new byte[512];
				int bytes  = ReceiveStream.Read(read, 0, 512);


				string InnerHtml = "";
				while (bytes > 0) 
				{

					// Note:
					// The following assumes that the response uses UTF-8 as encoding.
					// If the content is sent in a ANSI codepage like 932 use something like this:
					//  Encoding encode = System.Text.Encoding.GetEncoding("shift-jis");
					Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
					InnerHtml = InnerHtml + encode.GetString(read, 0, bytes);
					//Debug.WriteLine(InnerHtml);
					bytes = ReceiveStream.Read(read, 0, 512);

				}
				

				log(tname + " GET Success");
			}
			catch (Exception e)
			{
				log(DateTime.Now + " " + e.ToString() + " GET Error", true);
			}  
			finally 
			{
				if(result!=null)
				result.Close();

			}
				

    }


		public static void postPage(String url, String payload, string tname) 
		{
			WebResponse result = null;

			try 
			{
			
				url=url.Replace("&amp;","&");
				WebRequest req = WebRequest.Create(url);
				req.Timeout = posttimeout;
				req.Method = "POST";
				req.ContentType = "application/x-www-form-urlencoded";
				
				StringBuilder UrlEncoded = new StringBuilder();
				Char[] reserved = {'?', '=', '&'};
				byte[] SomeBytes = null;

				if (payload != null) 
				{
					int i=0, j;
					while(i<payload.Length)
					{
						j=payload.IndexOfAny(reserved, i);
						if (j==-1)
						{
							UrlEncoded.Append(HttpUtility.UrlEncode(payload.Substring(i, payload.Length-i)));
							break;
						}
						UrlEncoded.Append(HttpUtility.UrlEncode(payload.Substring(i, j-i)));
						
						UrlEncoded.Append(payload.Substring(j,1));
						i = j+1;
					}
					SomeBytes = Encoding.UTF8.GetBytes(UrlEncoded.ToString());
					req.ContentLength = SomeBytes.Length;
					Stream newStream = req.GetRequestStream();
					newStream.Write(SomeBytes, 0, SomeBytes.Length);
					newStream.Close();
				} 
				else 
				{
					req.ContentLength = 0;
				}

				
				result = req.GetResponse();
				Stream ReceiveStream = result.GetResponseStream();
				Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
				StreamReader sr = new StreamReader( ReceiveStream, encode );
				//log("\r\nResponse stream received");
				
				Char[] read = new Char[256];
				int count = sr.Read( read, 0, 256 );
	
				while (count > 0) 
				{
					String str = new String(read, 0, count);
					//Debug.Write(str);
					count = sr.Read(read, 0, 256);
				}

				log(tname + " POST Success");
				
			} 
			catch(Exception e) 
			{
				log( tname + " POST error " + e.ToString(), true);
				
				
			} 
			finally 
			{
				if ( result != null ) 
				{
					result.Close();
				}
			}
		}

        public static string[] getURLVars() {


            string[] readVALSs = File.ReadAllLines(@ConfigurationManager.AppSettings["valuedatafile"].ToString());
            return readVALSs;


        }

		public static void log(string s) 
		{
			log( s, false) ;
		}

		public static void log(string s, bool err) 
		{
			
			Trace.WriteLine(DateTime.Now + ":" + s);
			if(err)
				Console.WriteLine(DateTime.Now + ":" + s);

		}

	}

    class RequestState
    {
        public string _threadInfo;
        public string _url;
        public WebRequest _request;


        public RequestState(WebRequest request, string threadinfo, string url)
        {
            this._threadInfo = threadinfo;
            this._request = request;
            this._url = url;
        }




    }

}
